package com.example.ItPhotoAlbumCloud.utils;


import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.slf4j.Logger;
import org.springframework.beans.BeansException;
import org.yaml.snakeyaml.constructor.DuplicateKeyException;

import java.util.UUID;

/**
 * 公共模板设计模式
 *  小仙 创建人 2023-03-12 08:54:11
 */
public abstract class CommonTemplate {

    /** 存储线程对应的traceId */
    private static final ThreadLocal<String> THREAD_LOCAL = new ThreadLocal<>();


    /**
     * 逻辑方法
     */
    protected abstract Object business() throws Exception;


    /**
     * 执行
     * @param request
     * @param template
     * @return
     */
    public static Object run(Logger logger, CommonTemplate template, Object... request) {
        return handle(logger, template, request);
    }


    /**
     * 逻辑执行方法
     * @param request
     * @param logger
     * @param template
     * @return
     */
    private static Object handle(Logger logger, CommonTemplate template, Object... request) {

        setThreadTrace(request);

        try {

            LoggerUtils.info(logger, "请求入参:{0}", JSON.toJSONString(request));

            // 执行逻辑代码
            Object result = template.business();

            // 设置结果TRACE
            if (result instanceof JSONObject) {
                ((JSONObject) result).put("traceId", getTraceId());
            } else if (result instanceof CommonResult) {
                CommonResult r = (CommonResult) result;
                if (StringUtils.isBlank(r.getTraceId())) {
                    r.setTraceId(getTraceId());
                }
            }

            // 打印结果
            LoggerUtils.info(logger, "返回结果:{0}", result);

            // 返回结果
            return result;

        } catch (Throwable e) {

            // 打印错误日志
            LoggerUtils.error(e, logger, "执行异常，错误信息:{0}, 请求参数:{1}", e.getMessage(), JSON.toJSONString(request));

            // 获取执行异常时返回结果
            CommonResult res = failHandle(e);
            res.setTraceId(getTraceId());
            return res;

        } finally {

            // 执行完毕后，删除线程对应的TraceId
            THREAD_LOCAL.remove();
        }
    }


    /**
     * 失败的处理
     * @param cause
     * @return
     */
    private static CommonResult failHandle(Throwable cause) {
        if (cause instanceof CommonException) {
            CommonException ce = (CommonException) cause;
            return new CommonResult(ce.getErrorCode(), ce.getErrorMsg());
        } else if (cause instanceof DuplicateKeyException) {
            return new CommonResult("IDEMPOTENT_ERROR", "已有相同数据，无需重复提交");
        } else if (cause instanceof BeansException) {
            return new CommonResult("NO_SERVICE", "未匹配到对应服务");
        } else {
            return new CommonResult("ERROR", "执行失败");
        }
    }


    /**
     * 获取线程TRACE_ID
     *
     * @return
     */
    public static String getTraceId() {
        return THREAD_LOCAL.get();
    }

    /**
     * 设置线程TRACE_ID
     */
    private static void setThreadTrace(Object... request) {
        String requestTraceId = null;
        if (null != request) {
            for (Object item : request) {
                if (item instanceof JSONObject) {
                    requestTraceId = ((JSONObject) item).getString("traceId");
                    break;
                }
            }
        }

        if (null == THREAD_LOCAL.get()){
            THREAD_LOCAL.set(StringUtils.isNotBlank(requestTraceId) ? requestTraceId : UUID.randomUUID().toString().replace("-", ""));
        }
    }
}

